/**
 * Copyright (C) 2009 Lazaro Brito
 *
 * This file is part of jIRC.
 * 
 * jIRC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * jIRC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with jIRC.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.lazaro.jirc;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedList;

import org.lazaro.jirc.irc.Channel;
import org.lazaro.jirc.irc.Target;
import org.lazaro.jirc.irc.User;
import org.lazaro.jirc.irc.Server;
import org.lazaro.jirc.proto.IRCProtocol;
import org.lazaro.jirc.msg.TopicHandler;
import org.lazaro.jirc.msg.MessageHandler;
import org.lazaro.jirc.msg.KickHandler;

/**
 * @author Lazaro Brito
 *
 */
public class IRC {
	private Socket socket = null;
	private InetSocketAddress address = null;
	private BufferedReader bufferedReader = null;
	private BufferedWriter bufferedWriter = null;

	private IRCProtocol protocol = new IRCProtocol(this);
	private IRCDetails details = new IRCDetails(this);
	private boolean connected = false;
	private boolean hasRegistered = false;

	private LinkedList<MessageHandler> messageHandlers = new LinkedList<MessageHandler>();
	private LinkedList<TopicHandler> topicHandlers = new LinkedList<TopicHandler>();
	private LinkedList<KickHandler> kickHandlers = new LinkedList<KickHandler>();

	private HashMap<String, Channel> currentChannels = new HashMap<String, Channel>();
	private HashMap<String, User> knownUsers = new HashMap<String, User>();
	private HashMap<String, Server> currentServers = new HashMap<String, Server>();

	private Target currentTarget = null;

	public IRC(InetSocketAddress address) throws IOException {
		this.address = address;
		this.socket = new Socket(address.getAddress(), address.getPort());
		if(!socket.isConnected()) {
			throw new RuntimeException("Invalid socket, not connected!");
		}
		bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		
		connected = true;
	}

	public IRC(String host, int port) throws IOException {
		this(new InetSocketAddress(host, port));
	}

	public InetSocketAddress getSocketAddress() {
		return address;
	}

	public boolean isConnected() {
		return connected;
	}

	public void setConnected(boolean connected) {
		this.connected = connected;
	}

	public BufferedReader getReader() {
		return bufferedReader;
	}

	public BufferedWriter getWriter() {
		return bufferedWriter;
	}

	public IRCDetails getDetails() {
		return details;
	}

	public IRCProtocol getProtocol() {
		return protocol;
	}

	public boolean isHasRegistered() {
		return hasRegistered;
	}

	public void setHasRegistered(boolean hasRegistered) {
		this.hasRegistered = hasRegistered;	
	}

	public void addMessageHandler(MessageHandler mh) {
		messageHandlers.addLast(mh);
	}

	public void removeMessageHandler(MessageHandler mh) {
		messageHandlers.remove(mh);
	}

	public LinkedList<MessageHandler> getMessageHandlers() {
		return messageHandlers;
	}

	public void addTopicHandler(TopicHandler th) {
		topicHandlers.addLast(th);
	}

	public void removeTopicHandler(TopicHandler th) {
		topicHandlers.remove(th);
	}

	public LinkedList<TopicHandler> getTopicHandlers() {
		return topicHandlers;
	}

	public void addKickHandler(KickHandler kh) {
		kickHandlers.addLast(kh);
	}

	public void removeKickHandler(KickHandler kh) {
		kickHandlers.remove(kh);
	}

	public LinkedList<KickHandler> getKickHandlers() {
		return kickHandlers;
	}

	public Target getCurrentTarget() {
		return currentTarget;
	}

	public void setCurrentTarget(Target currentTarget) {
		this.currentTarget = currentTarget;
	}

	public HashMap<String, Channel> getCurrentChannels() {
		return currentChannels;
	}

	public HashMap<String, User> getKnownUsers() {
		return knownUsers;
	}

	public HashMap<String, Server> getCurrentServers() {
		return currentServers;
	}

	public Target findTarget(String name) {
		if(name.startsWith("#")) { // TODO Don't know if there are any more prefixes.
			if(currentChannels.containsKey(name)) {
				return currentChannels.get(name);
			}
		}
		if(knownUsers.containsKey(name)) {
			return knownUsers.get(name);
		} else if(currentServers.containsKey(name)) {
			return currentServers.get(name);
		}
		return null;
	}
}